#include "StdAfx.h"
#include "user.h"
#include "GameMain.h"
#include "logproc.h"
#include "..\include\readscript.h"
#include "..\common\winutil.h"
#include "ResetSystem.h"
#include "GameShop.h"
#include "Gate.h"
#include "ObjCalCharacter.h"

#ifdef __CUSTOMS__

ResetSystem		g_ResetSystem;

ResetSystem::ResetSystem()
{
	this->Init();
}

ResetSystem::~ResetSystem()
{
}

void ResetSystem::Init()
{
	ZeroMemory(this->m_GroupData, sizeof(this->m_GroupData));
	this->m_GroupLoadedCount	= 0;
	this->m_MaxMoney			= 0;
	this->m_ReqCleanInventory	= true;
	this->m_ShopCleaning		= true;
	this->m_ResetStats			= true;
	this->m_ResetPoints			= true;
	this->m_NpcID				= 0;
	this->m_NpcMap				= 0;
	this->m_NpcX				= 0;
	this->m_NpcY				= 0;
	this->m_DynamicExp			= 0;
	this->m_DynamicExpMin		= 0.0f;
	this->m_DynamicExpPercent	= 0.0f;
}

void ResetSystem::Load()
{
	this->Init();
	this->ReadGroupData(gDirPath.GetNewPath("Custom\\ResetGroup.txt"));
	this->ReadMainData(gDirPath.GetNewPath("Custom\\ResetMain.ini"));
}

void ResetSystem::ReadGroupData(char * File)
{
	SMDToken Token;
	SMDFile = fopen(File, "r");

	if (!SMDFile)
	{
		MsgBox("[ResetSystem] %s file not found", File);
		return;
	}

	while (true)
	{
		Token = GetToken();

		if (Token == END)
		{
			break;
		}

		if (Token != NUMBER)
		{
			continue;
		}

		int GroupID = TokenNumber;
		Token = GetToken();
		this->m_GroupData[GroupID].MinReset		= TokenNumber;
		Token = GetToken();
		this->m_GroupData[GroupID].MaxReset		= TokenNumber;
		Token = GetToken();
		this->m_GroupData[GroupID].ReqLevel		= TokenNumber;
		Token = GetToken();
		this->m_GroupData[GroupID].ReqMoney		= TokenNumber;
		Token = GetToken();
		this->m_GroupData[GroupID].ItemCount	= TokenNumber;
		int RewardPerGroup	= 0;

		while (true)
		{
			if (RewardPerGroup >= MAX_TYPE_PLAYER)
			{
				break;
			}

			Token = GetToken();
			this->m_GroupData[GroupID].RewardData[RewardPerGroup].LevelPoint = TokenNumber;
			Token = GetToken();
			this->m_GroupData[GroupID].RewardData[RewardPerGroup].GensPoint = TokenNumber;
			Token = GetToken();
			this->m_GroupData[GroupID].RewardData[RewardPerGroup].WCoinC = TokenNumber;
			Token = GetToken();
			this->m_GroupData[GroupID].RewardData[RewardPerGroup].WCoinP = TokenNumber;
			Token = GetToken();
			this->m_GroupData[GroupID].RewardData[RewardPerGroup].GoblinPoint = TokenNumber;
			RewardPerGroup++;
		}

		int ItemPerGroup = 0;

		while (true)
		{
			if (ItemPerGroup >= this->m_GroupData[GroupID].ItemCount)
			{
				break;
			}

			Token = GetToken();
			this->m_GroupData[GroupID].ItemData[ItemPerGroup].ID			= TokenNumber;
			Token = GetToken();
			this->m_GroupData[GroupID].ItemData[ItemPerGroup].MinLevel		= TokenNumber;
			Token = GetToken();
			this->m_GroupData[GroupID].ItemData[ItemPerGroup].MaxLevel		= TokenNumber;
			Token = GetToken();
			this->m_GroupData[GroupID].ItemData[ItemPerGroup].MinOption		= TokenNumber;
			Token = GetToken();
			this->m_GroupData[GroupID].ItemData[ItemPerGroup].MaxOption		= TokenNumber;
			Token = GetToken();
			this->m_GroupData[GroupID].ItemData[ItemPerGroup].IsLuck		= TokenNumber;
			Token = GetToken();
			this->m_GroupData[GroupID].ItemData[ItemPerGroup].IsSkill		= TokenNumber;
			Token = GetToken();
			this->m_GroupData[GroupID].ItemData[ItemPerGroup].IsExcellent	= TokenNumber;
			Token = GetToken();
			this->m_GroupData[GroupID].ItemData[ItemPerGroup].IsAncient		= TokenNumber;
			Token = GetToken();
			this->m_GroupData[GroupID].ItemData[ItemPerGroup].IsSocket		= TokenNumber;
			ItemPerGroup++;
		}

		this->m_GroupLoadedCount++;

		if (this->m_GroupLoadedCount >= MAX_RESET_GROUP)
		{
			MsgBox("[ResetSystem] m_GroupLoadedCount error [%d]", this->m_GroupLoadedCount);
		}
	}

	fclose(SMDFile);
#if ( RESETSYSTEM_DEBUG == 1 )
	LogAddC(2, "[DEBUG] [%s] Loaded Groups: %d", __FUNCTION__, this->m_GroupLoadedCount);

	for(int i = 0; i < this->m_GroupLoadedCount; i++)
	{
		LogAddC(2, "%d", i);
		LogAddC(2, "%d %d %d %d %d", this->m_GroupData[i].MinReset, this->m_GroupData[i].MaxReset,
			this->m_GroupData[i].ReqLevel, this->m_GroupData[i].ReqMoney, this->m_GroupData[i].ItemCount);

		for(int k = 0; k < 7; k++)
		{
			LogAddC(2, "%d %d %d %d %d", this->m_GroupData[i].RewardData[k].LevelPoint,
				this->m_GroupData[i].RewardData[k].GensPoint, this->m_GroupData[i].RewardData[k].WCoinC,
				this->m_GroupData[i].RewardData[k].WCoinP, this->m_GroupData[i].RewardData[k].GoblinPoint);
		}

		for(int j = 0; j < this->m_GroupData[i].ItemCount; j++)
		{
			LogAddC(2, "%d %d %d %d %d %d %d %d %d", this->m_GroupData[i].ItemData[j].ID,
				this->m_GroupData[i].ItemData[j].MinLevel,
				this->m_GroupData[i].ItemData[j].MaxLevel, this->m_GroupData[i].ItemData[j].MinOption,
				this->m_GroupData[i].ItemData[j].MaxOption, this->m_GroupData[i].ItemData[j].IsLuck,
				this->m_GroupData[i].ItemData[j].IsExcellent, this->m_GroupData[i].ItemData[j].IsAncient,
				this->m_GroupData[i].ItemData[j].IsSocket);
		}

		LogAddC(2, "end");
	}

#endif
}

void ResetSystem::ReadMainData(char * File)
{
	this->m_MaxMoney			= GetPrivateProfileInt("Common", "MaxMoney", 0, File);
	this->m_ShopCleaning		= GetPrivateProfileInt("Common", "PShopCleaning", 0, File);
	this->m_ReqCleanInventory	= GetPrivateProfileInt("Common", "InventoryCheck", 0, File);
	this->m_ResetStats			= GetPrivateProfileInt("Common", "ResetStats", 1, File);
	this->m_ResetPoints			= GetPrivateProfileInt("Common", "ResetPoints", 1, File);
	this->m_NpcMap				= GetPrivateProfileInt("NPC", "Map", 0, File);
	this->m_NpcID				= GetPrivateProfileInt("NPC", "ID", 0, File);
	this->m_NpcMap				= GetPrivateProfileInt("NPC", "Map", 0, File);
	this->m_NpcX				= GetPrivateProfileInt("NPC", "X", 0, File);
	this->m_NpcY				= GetPrivateProfileInt("NPC", "Y", 0, File);
	this->m_DynamicExp			= GetPrivateProfileInt("Experience", "DynamicExp", 0, File);
	this->m_DynamicExpMin		= GetPrivateProfileFloat("Experience", "MinExpRate", 1.0f, File);
	this->m_DynamicExpPercent	= GetPrivateProfileFloat("Experience", "Percent", 0.2f, File);
}

int ResetSystem::GetResetMoney(LPOBJ lpUser)
{
	int Group = this->GetResetGroup(lpUser);

	if (Group == -1)
	{
		return -1;
	}

	int Money = this->m_GroupData[this->GetResetGroup(lpUser)].ReqMoney * (lpUser->Reset + 1);

	if (Money > this->m_MaxMoney)
	{
		Money = this->m_MaxMoney;
	}

	return Money;
}

int ResetSystem::GetResetGroup(LPOBJ lpUser)
{
	for(int Group = 0; Group < this->m_GroupLoadedCount; Group++)
	{
		if (lpUser->Reset >= this->m_GroupData[Group].MinReset
			&& lpUser->Reset < this->m_GroupData[Group].MaxReset)
		{
			return Group;
		}
	}

	return -1;
}

bool ResetSystem::SearchQuestItem(LPOBJ lpUser, BYTE QuestItemID)
{
	if (this->GetResetGroup(lpUser) == (int) - 1)
	{
		LogAddC(2, "[ResetSystem] [%s] [%s] Invalid group", lpUser->AccountID, lpUser->Name);
		return false;
	}

	WORD ItemID = this->m_GroupData[this->GetResetGroup(lpUser)].ItemData[QuestItemID].ID;

	for(int i = INVETORY_WEAR_SIZE; i < MAIN_INVENTORY_SIZE; i++)
	{
		if (!lpUser->pInventory[i].IsItem() || lpUser->pInventory[i].m_Type != ItemID)
		{
			continue;
		}

		if (lpUser->pInventory[i].m_Level < this->m_GroupData[this->GetResetGroup(lpUser)].ItemData[QuestItemID].MinLevel
			|| lpUser->pInventory[i].m_Level > this->m_GroupData[this->GetResetGroup(lpUser)].ItemData[QuestItemID].MaxLevel)
		{
			continue;
		}

		if (lpUser->pInventory[i].m_Option3 < this->m_GroupData[this->GetResetGroup(lpUser)].ItemData[QuestItemID].MinOption
			|| lpUser->pInventory[i].m_Option3 > this->m_GroupData[this->GetResetGroup(lpUser)].ItemData[QuestItemID].MaxOption)
		{
			continue;
		}

		if (this->m_GroupData[this->GetResetGroup(lpUser)].ItemData[QuestItemID].IsLuck != 2)
		{
			if (lpUser->pInventory[i].m_Option2 != this->m_GroupData[this->GetResetGroup(lpUser)].ItemData[QuestItemID].IsLuck)
			{
				continue;
			}
		}

		if (this->m_GroupData[this->GetResetGroup(lpUser)].ItemData[QuestItemID].IsSkill != 2)
		{
			if (lpUser->pInventory[i].m_Option1 != this->m_GroupData[this->GetResetGroup(lpUser)].ItemData[QuestItemID].IsSkill)
			{
				continue;
			}
		}

		if (this->m_GroupData[this->GetResetGroup(lpUser)].ItemData[QuestItemID].IsExcellent)
		{
			if (!lpUser->pInventory[i].m_NewOption)
			{
				continue;
			}
		}

		if (this->m_GroupData[this->GetResetGroup(lpUser)].ItemData[QuestItemID].IsAncient)
		{
			if (!lpUser->pInventory[i].m_SetOption)
			{
				continue;
			}
		}

		if (this->m_GroupData[this->GetResetGroup(lpUser)].ItemData[QuestItemID].IsSocket)
		{
			if (!gItemSocketOption.IsEnableSocketItem(ItemID))
			{
				continue;
			}
		}

		return true;
	}

	return false;
}

bool ResetSystem::DeleteQuestItem(LPOBJ lpUser, BYTE QuestItemID)
{
	if (this->GetResetGroup(lpUser) == (int) - 1)
	{
		LogAddC(2, "[ResetSystem] [%s] [%s] Invalid group", lpUser->AccountID, lpUser->Name);
		return false;
	}

	WORD ItemID = this->m_GroupData[this->GetResetGroup(lpUser)].ItemData[QuestItemID].ID;

	for(int i = INVETORY_WEAR_SIZE; i < MAIN_INVENTORY_SIZE; i++)
	{
		if (!lpUser->pInventory[i].IsItem() || lpUser->pInventory[i].m_Type != ItemID)
		{
			continue;
		}

		if (lpUser->pInventory[i].m_Level < this->m_GroupData[this->GetResetGroup(lpUser)].ItemData[QuestItemID].MinLevel
			|| lpUser->pInventory[i].m_Level > this->m_GroupData[this->GetResetGroup(lpUser)].ItemData[QuestItemID].MaxLevel)
		{
			continue;
		}

		if (lpUser->pInventory[i].m_Option3 < this->m_GroupData[this->GetResetGroup(lpUser)].ItemData[QuestItemID].MinOption
			|| lpUser->pInventory[i].m_Option3 > this->m_GroupData[this->GetResetGroup(lpUser)].ItemData[QuestItemID].MaxOption)
		{
			continue;
		}

		if (this->m_GroupData[this->GetResetGroup(lpUser)].ItemData[QuestItemID].IsLuck != 2)
		{
			if (lpUser->pInventory[i].m_Option2 != this->m_GroupData[this->GetResetGroup(lpUser)].ItemData[QuestItemID].IsLuck)
			{
				continue;
			}
		}

		if (this->m_GroupData[this->GetResetGroup(lpUser)].ItemData[QuestItemID].IsSkill != 2)
		{
			if (lpUser->pInventory[i].m_Option1 != this->m_GroupData[this->GetResetGroup(lpUser)].ItemData[QuestItemID].IsSkill)
			{
				continue;
			}
		}

		if (this->m_GroupData[this->GetResetGroup(lpUser)].ItemData[QuestItemID].IsExcellent)
		{
			if (!lpUser->pInventory[i].m_NewOption)
			{
				continue;
			}
		}

		if (this->m_GroupData[this->GetResetGroup(lpUser)].ItemData[QuestItemID].IsAncient)
		{
			if (!lpUser->pInventory[i].m_SetOption)
			{
				continue;
			}
		}

		if (this->m_GroupData[this->GetResetGroup(lpUser)].ItemData[QuestItemID].IsSocket)
		{
			if (!gItemSocketOption.IsEnableSocketItem(ItemID))
			{
				continue;
			}
		}

		gObjInventoryDeleteItem(lpUser->m_Index, i);
		GCInventoryItemDeleteSend(lpUser->m_Index, i, 1);
		return true;
	}

	return false;
}

bool ResetSystem::Dialog(LPOBJ lpUser, LPOBJ lpNpc)
{
	if (lpNpc->Class		== this->m_NpcID
		&&	lpNpc->MapNumber	== this->m_NpcMap
		&&	lpNpc->X			== this->m_NpcX
		&&	lpNpc->Y			== this->m_NpcY)
	{
		this->SendResetData(lpUser, true);
		return true;
	}

	return false;
}

bool ResetSystem::CheckAllReq(LPOBJ lpUser)
{
	if (this->GetResetGroup(lpUser) == (int) - 1)
	{
		LogAddC(2, "[ResetSystem] [%s] [%s] Invalid group", lpUser->AccountID, lpUser->Name);
		return false;
	}

	int	ResetGroup = this->GetResetGroup(lpUser);

	if (lpUser->Level < this->m_GroupData[ResetGroup].ReqLevel)
	{
		return false;
	}

	int Money = this->GetResetMoney(lpUser);

	if (Money == -1)
	{
		return false;
	}

	if (lpUser->Money < Money)
	{
		return false;
	}

	if (this->m_ReqCleanInventory)
	{
		for(int i = 0; i < 12; i++)
		{
			if (lpUser->pInventory[i].IsItem())
			{
				return false;
			}
		}
	}

	if (this->m_GroupData[ResetGroup].ItemCount > 0)
	{
		for(int i = 0; i < this->m_GroupData[ResetGroup].ItemCount; i++)
		{
			if (!this->SearchQuestItem(lpUser, i))
			{
				return false;
			}
		}
	}

	return true;
}

void ResetSystem::FinishResetReq(LPOBJ lpUser)
{
	if (this->GetResetGroup(lpUser) == (int) - 1)
	{
		LogAddC(2, "[ResetSystem] [%s] [%s] Invalid group", lpUser->AccountID, lpUser->Name);
		return;
	}

	RESET_REQ_USERDATA pSend;
	pSend.h.set((LPBYTE)&pSend, ResetProtocol::Case, ResetProtocol::ResetFinish, sizeof(pSend));
	int ResetGroup = this->GetResetGroup(lpUser);

	if (!this->CheckAllReq(lpUser))
	{
		GCServerMsgStringSend("You must finish all the requirements for make Reset", lpUser->m_Index, 1);
		return;
	}

	if (this->m_GroupData[ResetGroup].ItemCount > 0)
	{
		for(int i = 0; i < this->m_GroupData[ResetGroup].ItemCount; i++)
		{
			if (!this->DeleteQuestItem(lpUser, i))
			{
				GCServerMsgStringSend("Please check quest items positions", lpUser->m_Index, 1);
				return;
			}
		}
	}

	lpUser->Level		= 1;
	lpUser->Experience	= 0;

	if (this->m_ResetStats)
	{
		lpUser->Strength	= DCInfo.DefClass[lpUser->Class].Strength;
		lpUser->Dexterity	= DCInfo.DefClass[lpUser->Class].Dexterity;
		lpUser->Energy		= DCInfo.DefClass[lpUser->Class].Energy;
		lpUser->Vitality	= DCInfo.DefClass[lpUser->Class].Vitality;
		lpUser->Leadership	= DCInfo.DefClass[lpUser->Class].Leadership;
	}

	if (m_ResetPoints)
	{
		lpUser->LevelUpPoint = this->m_GroupData[ResetGroup].RewardData[lpUser->Class].LevelPoint * (lpUser->Reset + 1);
	}
	else
	{
		lpUser->LevelUpPoint += this->m_GroupData[ResetGroup].RewardData[lpUser->Class].LevelPoint * (lpUser->Reset + 1);
	}

#ifdef GENS
	lpUser->m_ContributePoint		+= this->m_GroupData[ResetGroup].RewardData[lpUser->Class].GensPoint;
#endif
	lpUser->GameShop.WCoinC			+= this->m_GroupData[ResetGroup].RewardData[lpUser->Class].WCoinC;
	lpUser->GameShop.WCoinP			+= this->m_GroupData[ResetGroup].RewardData[lpUser->Class].WCoinP;
	lpUser->GameShop.GoblinPoint	+= this->m_GroupData[ResetGroup].RewardData[lpUser->Class].GoblinPoint;
	lpUser->Money					-= this->GetResetMoney(lpUser);
	GCMoneySend(lpUser->m_Index, lpUser->Money);
	lpUser->Reset++;
	int Gate = -1;
	short X, Y, Level;
	BYTE MapNumber, Dir;

	if (lpUser->Class == CLASS_ELF)
	{
		Gate = 27;
	}
	else if (lpUser->Class == CLASS_SUMMONER)
	{
		Gate = 267;
	}
	else
	{
		Gate = 17;
	}

	gGateC.GetGate(Gate, (short &)X, (short &)Y, (BYTE &)MapNumber, (BYTE &)Dir, (short &)Level);
	lpUser->MapNumber	= MapNumber;
	lpUser->X			= X;
	lpUser->Y			= Y;
	lpUser->Dir			= Dir;
	DataSend(lpUser->m_Index, (LPBYTE)&pSend, pSend.h.size);
	g_ResetSystem.SendResetData(lpUser, false);
	gObjCloseSet(lpUser->m_Index, 1);
}

void ResetSystem::SendResetData(LPOBJ lpUser, bool ByDialog)
{
	if (this->GetResetGroup(lpUser) == (int) - 1)
	{
		LogAddC(2, "[ResetSystem] [%s] [%s] Invalid group", lpUser->AccountID, lpUser->Name);
		return;
	}

	RESET_ANS_USERDATA pSend;
	pSend.h.set((LPBYTE)&pSend, ResetProtocol::Case, ResetProtocol::UserData, sizeof(pSend));
	pSend.ByDialog	= ByDialog;
	pSend.Reset		= lpUser->Reset;

	if (this->m_GroupData[this->GetResetGroup(lpUser)].ItemCount > 0)
	{
		for(int i = 0; i < this->m_GroupData[this->GetResetGroup(lpUser)].ItemCount; i++)
		{
			pSend.ItemCheck[i] = true;

			if (!this->SearchQuestItem(lpUser, i))
			{
				pSend.ItemCheck[i] = false;
			}
		}
	}

	DataSend(lpUser->m_Index, (LPBYTE)&pSend, pSend.h.size);
}

float ResetSystem::GetPrivateProfileFloat(char * Section, char * Key, float DefaultValue, char * File)
{
	char	Result[255];
	char	Default[255];
	float	FloatResult;
	wsprintf(Default, "%f", DefaultValue);
	GetPrivateProfileStringA(Section, Key, Default, Result, 255, File);
	FloatResult = atof(Result);
	return FloatResult;
}

float ResetSystem::GetDynamicExp(LPOBJ lpUser)
{
	if (!this->m_DynamicExp)
	{
		return gAddExperience;
	}

	float AddExperience = 0;
	AddExperience = gAddExperience - (this->m_DynamicExpPercent * lpUser->Reset);

	if (AddExperience < this->m_DynamicExpMin)
	{
		AddExperience = this->m_DynamicExpMin;
	}

	return AddExperience;
}

#endif